package u.can.i.up.gexf;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import u.can.i.up.db.postgresql.Aliases;

public class AliasesReader {

	private static volatile AliasesReader instant = new AliasesReader();

	Logger logger = LogManager.getLogger(AliasesGenerator.class);

	public static AliasesReader getInstant() {
		return instant;
	}

	public List<Aliases> readEdgesFromCSV(String csvPath) {
		List<Aliases> mAliaseList = new ArrayList<Aliases>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(csvPath));
			String tempString = null;
			while ((tempString = reader.readLine()) != null) {
				if (tempString.startsWith("Source")) {
					continue;
				}
				String[] tmp = tempString.trim().split("\t");
				// if (tmp[0].equals(tmp[1])) {
				// continue;
				// }
				Aliases aliase = new Aliases();
				aliase.setSid(Integer.parseInt(tmp[0]));
				aliase.setTid(Integer.parseInt(tmp[1]));
				mAliaseList.add(aliase);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
			try {
				reader.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		return mAliaseList;
	}

	public Map<Integer, String> readNodesFromCSV(String csvPath) {
		Map<Integer, String> mNodeList = new HashMap<Integer, String>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(csvPath));
			String tempString = null;
			while ((tempString = reader.readLine()) != null) {
				if (tempString.startsWith("id")) {
					continue;
				}
				String[] tmp = tempString.trim().split("\t");
				if (tmp[0].equals(tmp[1])) {
					continue;
				}
				mNodeList.put(Integer.parseInt(tmp[0]), tmp[1]);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
			try {
				reader.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		return mNodeList;
	}

	public void updateAppEdgesWithNodes(List<Aliases> mAliaseList, Map<Integer, String> mNodeMap) {
		if (mAliaseList == null || mAliaseList.isEmpty()) {
			return;
		}
		for (Aliases aliases : mAliaseList) {
			aliases.setSapp(mNodeMap.get(aliases.getSid()));
			aliases.setTapp(mNodeMap.get(aliases.getTid()));
		}
	}
	
	public void updateComponentEdgesWithNodes(List<Aliases> mAliaseList, Map<Integer, String> mNodeMap) {
		if (mAliaseList == null || mAliaseList.isEmpty()) {
			return;
		}
		for (Aliases aliases : mAliaseList) {
			aliases.setScomponent(mNodeMap.get(aliases.getSid()));
			aliases.setTcomponent(mNodeMap.get(aliases.getTid()));
		}
	}

	public void updateLinkMap(List<Aliases> mAliaseList, Map<Integer, HashSet<Integer>> inLinkMap,
			Map<Integer, HashSet<Integer>> outLinkMap) {
		for (Aliases aliases : mAliaseList) {
			int sid = aliases.getSid();
			int tid = aliases.getTid();
			insertIntoMap(outLinkMap, sid, tid);
			insertIntoMap(inLinkMap, tid, sid);
		}
	}

	private void insertIntoMap(Map<Integer, HashSet<Integer>> map, int source, int target) {
		map = (map != null) ? map : (new HashMap<Integer, HashSet<Integer>>());
		HashSet<Integer> intList = map.get(source);
		if (intList == null) {
			intList = new HashSet<Integer>();
			intList.add(target);
			map.put(source, intList);
		} else {
			intList.add(target);
		}
	}

	/**
	 * @param inLinkMap
	 *            链入map, key为tid, values为sid;
	 * @param outLinkMap
	 *            链出map, key为sid, values为tid;
	 * @param target
	 *            目标id;
	 * @param distance
	 *            距离, 即迭代次数, 为0时不迭代, 只计算当前节点的前驱节点.
	 * @return 影响的应用集合.
	 */
	public HashSet<Integer> findAffectedApps(Map<Integer, HashSet<Integer>> inLinkMap,
			Map<Integer, HashSet<Integer>> outLinkMap, int target, int distance) {
		HashSet<Integer> affectedAppSet = new HashSet<Integer>();
		HashSet<Integer> tmpSet = new HashSet<Integer>();
		findNext(outLinkMap, tmpSet, target, distance);
		// 对tmpSet中所有的target找影响的应用, 并添加到affectedAppSet中.
		for (int tmp : tmpSet) {
			findPrevious(inLinkMap, affectedAppSet, tmp, ((distance == 0) ? 1 : distance));
		}
		affectedAppSet.removeAll(tmpSet);
		return affectedAppSet;
	}

	private void findNext(Map<Integer, HashSet<Integer>> outLinkMap, HashSet<Integer> tmpSet, int target,
			int distance) {
		if (distance == 0) {
			tmpSet.add(target);
		}
		if (distance > 0) {
			HashSet<Integer> tmp = outLinkMap.get(target);
			if (tmp == null || tmp.isEmpty()) {
			} else {
				for (int subTarget : tmp) {
					// if (subTarget != 1588811)
					findNext(outLinkMap, tmpSet, subTarget, distance - 1);
				}
			}
			tmpSet.add(target);
		}
	}

	private void findPrevious(Map<Integer, HashSet<Integer>> inLinkMap, HashSet<Integer> tmpSet, int target,
			int distance) {
		if (distance == 0) {
			tmpSet.add(target);
		}
		if (distance > 0) {
			HashSet<Integer> tmp = inLinkMap.get(target);
			if (tmp == null || tmp.isEmpty()) {
			} else {
				for (int subTarget : tmp) {
					// if (subTarget != 1588811)
					findPrevious(inLinkMap, tmpSet, subTarget, distance - 1);
				}
			}
			tmpSet.add(target);
		}
	}

}
